<template>
  <div class="bg-box" v-show="isShowPlayList" @click="isShowPlayList = false"></div>
  <div class="player-container slide-in-bottom" v-if="isShow">
    <transition>
      <PlayList v-show="isShowPlayList" @closePlayList="isShowPlayList = false" @selectPlaySong="playSong" @clearAudio="clearAudio" />
    </transition>
    <audio ref="audioPlayer" @play="playing" @ended="playEnd" @timeupdate="timeupdate"></audio>
    <div class="left">
      <div class="playing-list" @click.stop="isShowPlayList = !isShowPlayList">
        <n-icon class="icon">
          <MusicalNotesOutline />
        </n-icon>
      </div>
      <div class="info">
        <div class="title" v-html="songInformation.title"></div>
        <div class="author">{{ songInformation.author }}</div>
      </div>
    </div>
    <div class="center">
      <span class="operation">
        <span class="arrow" @click="cutSong('previous')">
          <n-icon>
            <PlaySkipBackCircleOutline />
          </n-icon>
        </span>
        <div class="circle" @click="switchPlayState" @mouseenter="audioData.isShowPlayState = true" @mouseleave="audioData.isShowPlayState = false">
          <img ref="imgRotateDom" :src="songInformation.pic.replace(/^([a-zA-Z]+:\/\/)?/, 'https://')" />
          <div class="playState" v-show="audioData.isShowPlayState">
            <n-icon size="50" v-show="!audioData.playState"><LogoGooglePlaystore /></n-icon>
            <n-icon size="50" v-show="audioData.playState"><Pause /></n-icon>
          </div>
        </div>
        <span class="arrow" @click="cutSong('next')">
          <n-icon>
            <PlaySkipForwardCircleOutline />
          </n-icon>
        </span>
      </span>
      <div class="adjust" @mouseenter="adjustShow = true" @mouseleave="adjustShow = false">
        <div class="time" v-show="!adjustShow">{{ songInformation.currentTime }}/{{ songInformation.duration }}</div>
        <div v-show="adjustShow" class="slider-container">
          <div class="slider">
            <n-icon>
              <AirplaneOutline />
            </n-icon>
            <n-slider v-model:value="audioData.playTo" :step="1" :max="songInformation.timeSlider" :on-update:value="changeplayTo" :tooltip="false" />
          </div>
          <div class="slider">
            <n-icon>
              <VolumeHighOutline />
            </n-icon>
            <n-slider v-model:value="audioData.volume" :step="0.01" :max="1" :on-update:value="changeVolume" :tooltip="false" />
          </div>
        </div>
      </div>
    </div>

    <div class="right">
      <n-icon class="icon like" @click="addSongMenu">
        <HeartTwotone />
      </n-icon>
      <img :src="modeInfo.modeList[modeInfo.mode]" @click="changeMode" />
      <n-icon class="icon">
        <BookOutline />
      </n-icon>
      <n-icon class="icon">
        <ChevronUp />
      </n-icon>
    </div>
  </div>

  <OperateMenu :menuInfo="menuInfo" ref="addSongMenuDom" />
</template>

<script setup>
import { ref, reactive, onMounted } from 'vue';
import {
  MusicalNotesOutline,
  PlaySkipBackCircleOutline,
  PlaySkipForwardCircleOutline,
  AirplaneOutline,
  VolumeHighOutline,
  Add,
  BookOutline,
  ChevronUp,
  Pause,
  LogoGooglePlaystore,
} from '@vicons/ionicons5';
import { HeartTwotone } from '@vicons/antd';
import orderPlayMode from '/player/order.svg';
import randomPlayMode from '/player/random.svg';
import singleCyclePlayMode from '/player/singleCycle.svg';

onMounted(() => {
  if (localStorage.getObject('playingList').length !== 0) {
    songInformation.value = localStorage.getObject('playingList')[0];
    isShow.value = true;
    songInformation.value.currentTime = '0:00';
  }
});

const isShowPlayList = ref(false);
const audioPlayer = ref(null);
const adjustShow = ref(false);
const audioData = reactive({
  playState: false,
  isShowPlayState: false,
  volume: 0.5,
  playTo: 0,
});
const songInformation = ref({});

function changeplayTo(newPlay) {
  audioData.playTo = newPlay;
  audioPlayer.value.currentTime = newPlay;
}
function changeVolume(newVolume) {
  audioData.volume = newVolume;
  audioPlayer.value.volume = newVolume;
}
function switchPlayState() {
  audioData.paused = audioPlayer.value.paused;
  if (audioData.paused) {
    if (!audioPlayer.value.duration) {
      playSong(0);
      return;
    }
    audioPlayer.value.play();
    audioData.playState = true;
    imgRotate();
  } else {
    audioPlayer.value.pause();
    audioData.playState = false;
    window.cancelAnimationFrame(imgRotateInfo.animationFrameId);
  }
}

function playSong(index) {
  const songInfo = localStorage.getObject('playingList')[index];
  songInformation.value = { currentTime: '0:00', duration: '0:00', ...songInfo };
  if (audioPlayer.value) {
    const audioElement = audioPlayer.value;
    audioData.playState = false;
    // 检查浏览器是否支持 MSE
    if ('MediaSource' in window) {
      const mediaSource = new MediaSource();
      audioElement.src = URL.createObjectURL(mediaSource);
      mediaSource.addEventListener('sourceopen', async () => {
        // 打开 MSE 流源后，可以开始加载音频分段
        const sourceBuffer = mediaSource.addSourceBuffer('audio/mp4; codecs="mp4a.40.2"'); // 音频流类型
        try {
          let segmentResponse = null;
          if (songInfo.platform === 'bili') {
            const songStreamurl = await window.BiliAPI.getSongStreamUrl(songInfo);
            segmentResponse = await window.BiliAPI.getBiliAudio(songStreamurl); // 获取分段数据
          }
          if (segmentResponse) {
            // 将音频分段数据添加到 SourceBuffer 中
            sourceBuffer.appendBuffer(segmentResponse);
            // 播放结束后，可以根据需求加载更多的分段
            sourceBuffer.addEventListener('updateend', () => {
              // 如果有更多的音频分段，可以继续加载
              mediaSource.endOfStream();
              audioPlayer.value.play();
              songInformation.value.timeSlider = Math.floor(audioPlayer.value.duration);
              audioData.playState = true;
              songInformation.value.duration = formatMinutesSec(Math.floor(audioPlayer.value.duration));
            });
          }
        } catch (error) {
          console.error('加载音频分段时出错:', error);
        }
      });
    } else {
      console.error('浏览器不支持 MSE');
    }
  }
}

let isShow = ref(false);
function playerIsShow(newIsShow) {
  isShow.value = newIsShow;
}

function playing() {
  audioData.playTo = 0;
  imgRotateDom.value.style.transform = 'rotate(0)';
  imgRotate();
}

function playEnd() {
  audioData.playState = false;
  window.cancelAnimationFrame(imgRotateInfo.animationFrameId);
  imgRotateInfo.animationFrameId = null;
  imgRotateInfo.initAngle = 0;
  cutSong('next');
}

function formatMinutesSec(Sec) {
  const minutes = Math.floor(Sec / 60);
  const secs = Math.floor(Sec % 60);
  return `${minutes}:${secs < 10 ? '0' : ''}${secs}`;
}

function timeupdate() {
  if (!audioPlayer.value.currentTime) return;
  songInformation.value.currentTime = formatMinutesSec(audioPlayer.value.currentTime);
  audioData.playTo = audioPlayer.value.currentTime;
}

defineExpose({
  playerIsShow,
  playSong,
});

function cutSong(operate) {
  imgRotateInfo.initAngle = 0;
  const playingList = localStorage.getObject('playingList');
  let index = playingList.findIndex((item) => item.id === songInformation.value.id);
  if (modeInfo.mode === 1) {
    const randomIndex = Math.floor(Math.random() * playingList.length);
    if (randomIndex === index) {
      randomIndex += 1;
    }
    index = randomIndex;
  }
  switch (operate) {
    case 'previous':
      if (index === 0) index = playingList.length;
      playSong(index - 1);
      break;
    case 'next':
      if (index + 1 === playingList.length) index = -1;
      playSong(index + 1);
      break;
  }
}

const modeInfo = reactive({
  mode: 0,
  modeList: [orderPlayMode, randomPlayMode, singleCyclePlayMode],
});
function changeMode() {
  modeInfo.mode += 1;
  if (modeInfo.mode === 3) modeInfo.mode = 0;
  if (modeInfo.mode === 2) audioPlayer.value.loop = true;
  if (modeInfo.mode === 0 || modeInfo.mode === 1) audioPlayer.value.loop = false;
}

function clearAudio() {
  if (audioPlayer.value) {
    audioPlayer.value.pause();
    audioPlayer.value.currentTime = 0;
    audioPlayer.value.src = '';
    songInformation.value = {
      title: '',
      author: '',
      pic: '',
      duration: '',
      timeSlider: 0,
      timeSlider: 0,
      currentTime: '0:00',
    };
    isShow.value = false;
    isShowPlayList.value = false;
  }
}

const imgRotateDom = ref(null);
let imgRotateInfo = {
  initAngle: 0,
  animationFrameId: null,
};
function imgRotate() {
  if (!audioData.playState) return;
  imgRotateInfo.initAngle += 0.2;
  imgRotateDom.value.style.transform = `rotate(${imgRotateInfo.initAngle}deg)`;
  imgRotateInfo.animationFrameId = window.requestAnimationFrame(imgRotate);
}

const menuInfo = ref({});
const addSongMenuDom = ref(null);
function addSongMenu() {
  menuInfo.value = {
    type: 'add',
    songInfo: songInformation.value,
  };
  addSongMenuDom.value.updateSongMenuNameList();
  addSongMenuDom.value.operateInfo.isShow = true;
}
</script>

<style lang="scss" scoped>
@import '../../public/animation.css';
@mixin flex-center {
  display: flex;
  justify-content: center;
  align-items: center;
}
@mixin vertically-center {
  display: flex;
  align-items: center;
}
.bg-box {
  position: fixed;
  left: 0;
  top: 70px;
  width: 100vw;
  height: calc(100vh - 70px);
}
.player-container {
  @include vertically-center;
  justify-content: space-between;
  position: fixed;
  left: 1vw;
  bottom: 10px;
  width: 98vw;
  height: 120px;
  background-color: #fff;
  border-radius: 30px;
  transition: width 0.5s linear;
  box-shadow: 5px 5px 68px #c1c1c1, -5px -5px 68px #ffffff;
  z-index: 99;
  .left {
    @include vertically-center;

    .playing-list {
      @include flex-center;
      width: 110px;
      border-right: 1px solid #a9a9a9;
      font-size: 25px;

      .icon {
        border-radius: 3px;

        &:hover {
          color: #017afe;
          background-color: #f2f2f7;
        }
      }
    }

    .info {
      width: 210px;
      margin-left: 40px;

      .title {
        overflow: hidden;
        white-space: nowrap;
        text-overflow: ellipsis;
        font-size: 18px;
        font-weight: 700;
      }

      .author {
        font-size: 13px;
      }
    }
  }

  .center {
    width: 280px;
    margin-right: 50px;

    .operation {
      display: flex;
      justify-content: space-around;
      align-items: flex-end;
      height: 50px;

      .arrow {
        font-size: 50px;
        transform: translateY(20px);
      }

      .circle {
        position: relative;
        overflow: hidden;
        width: 100px;
        height: 100px;
        border-radius: 50%;
        img {
          width: 100%;
          height: 100%;
          object-fit: cover;
        }
        .playState {
          @include flex-center();
          position: absolute;
          left: 0;
          top: 0;
          width: 100px;
          height: 100px;
          background-color: rgba($color: #000000, $alpha: 0.8);
          color: #fff;
          opacity: 1;
        }
      }
    }

    .adjust {
      display: flex;
      justify-content: center;
      width: 100%;
      height: 30px;
      margin-top: 10px;
      font-size: 13px;

      .slider-container {
        display: flex;

        .slider {
          @include vertically-center();
          width: 120px;
          margin: 0 5px;
          font-size: 20px;

          &:hover {
            color: #017afe;
          }
        }
      }
    }
  }

  .right {
    display: flex;
    justify-content: space-between;
    width: 220px;
    margin-right: 30px;
    font-size: 25px;

    .icon {
      &:hover {
        color: #017afe;
      }
    }
    .like {
      &:hover {
        color: #fe0101;
      }
    }
    img {
      width: 25px;
      height: 25px;
      object-fit: contain;
    }
  }
}

:deep(.n-slider) {
  --n-fill-color: #2b99f4 !important;
  --n-fill-color-hover: #2b99f4 !important;
}
:deep(.n-slider .n-slider-handles .n-slider-handle-wrapper .n-slider-handle) {
  width: 15px;
  height: 15px;
  background-color: #017afe;
}
</style>
